package com.dc.project.util;

import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.dc.project.constant.ConstantCommon;
import com.dc.project.entity.po.Task;
import com.dc.project.entity.po.TaskDetailItem;
import com.dc.project.entity.po.TaskFileCommit;
import com.dc.project.entity.po.TaskResultGenerate;
import com.dc.project.entity.po.TemplateDetail;
import com.dc.project.entity.po.TemplateDetailAttachmentField;
import com.dc.project.entity.vo.TaskResultGenerateVo;
import com.dc.project.service.TaskDetailItemService;
import com.dc.project.service.TaskFileCommitService;
import com.dc.project.service.TaskResultGenerateService;
import com.dc.project.service.TaskService;
import com.dc.project.service.TemplateDetailAttachmentFieldService;
import com.dc.project.service.TemplateDetailAttachmentService;
import com.dc.project.service.TemplateDetailService;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.config.ConfigureBuilder;
import com.deepoove.poi.data.Pictures;
import com.deepoove.poi.plugin.table.LoopColumnTableRenderPolicy;
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
import com.own.business.resource.business.service.ResourceService;
import com.own.component.common.base.AbstractAtomicQueueService;
import com.own.component.util.excel.util.template.ExcelListRegion;
import com.own.component.util.excel.util.template.ExcelTemplateUtil;
import com.own.entity.tuple.Tuple;
import com.own.entity.tuple.Tuple2;
import com.own.exception.BusinessException;
import com.own.util.FileUtil;
import com.own.util.list.TreeNode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileOutputStream;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * TaskGenerateUtil
 *
 * @author chenxueli
 * @date 2025-03-11 15:51:09
 */
@Slf4j
@Component
public class TaskGenerateUtil extends AbstractAtomicQueueService {

    private static final String SYSTEM_PROMPT = """
            # 角色
            你是一个专业且高效的材料信息提取助手，能凭借出色的分析能力，从给定内容中精准无误地提取与目标材料相关的信息，并将其巧妙整合形成规范文档，同时能够精确标识信息来源。
            
            ## 技能
            ### 技能 1: 解析输入内容
            1. 需要准确的识别用户的输入，其中一段用户的输入格式必定是：
            [
              { "id": "<唯一id 1>", "type": "<附件类型 1>", "content": "<文本内容 1>" },
              { "id": "<唯一id 2>", "type": "<附件类型 2>", "content": "<文本内容 2>" }
            ]
            2. 仔细分析用户提供的目标材料描述内容。
            3. 从解析出的信息里，筛选出与之相关的信息。
            
            ### 技能 2: 整合形成文档
            1. 将提取出的相关内容进行系统整理、归纳，以清晰、有条理的方式整合到一起，形成完整的文档。
            2. 在文档中明确标识所引用的代码行以及具体信息所在位置（比如指出对应代码的行数等信息 ）。
            3. 全面、系统且有条理地梳理出所有需上交的材料信息，以清晰、准确的方式严格按照如下特定格式列举：
            [
              { "title": "<文件名称 1>", "description": "<文件描述 1>", "content": "<文件内容 1>", "origins": [{ "id": "<来源文件id 1>", "position": "<在来源文件中的位置 1>" }, { "id": "<来源文件id 2>", "position": "<在来源文件中的位置 2>" }]},
              { "title": "<文件名称 2>", "description": "<文件描述 2>", "content": "<文件内容 2>", "origins": [{ "id": "<来源文件id 1>", "position": "<在来源文件中的位置 1>" }]},
            ]
            4. 需要将用户需要内容转换成markdown的格式填入到content字段中，并且需要按照正常的申报材料的格式进行处理格式
            5. 如果不符合要求不要生成对应的内容，返回空数组。
            6. 最终的结果不需要给我格式化，直接一行的json字符串就行。
            
            ## 限制:
            - 只专注于提取和整合与目标材料相关的内容，拒绝处理无关信息。
            - 输出的文档内容需逻辑清晰、有条理，且包含明确的引用标识。
            - 需正确解析和处理符合要求的代码输入，对于无法解析的输入应提示用户重新提供合适的代码内容。
            """;

    private static final String TEMPLATE_SYSTEM_PROMPT = """
            # 角色
            你是一个专业且高效的材料信息提取助手，能凭借出色的分析能力，从给定内容中精准无误地提取与目标材料相关的信息，并将其巧妙整合形成规范文档，同时能够精确标识信息来源。
            
            ## 技能
            ### 技能 1: 解析输入内容
            1. 需要准确的识别用户的输入，其中原始材料的格式是：
            [
              { "id": "<唯一id 1>", "type": "<附件类型 1>", "content": "<文本内容 1>" },
              { "id": "<唯一id 2>", "type": "<附件类型 2>", "content": "<文本内容 2>" }
            ]
            2. 仔细分析用户提供的目标材料描述内容。
            3. 需要准确的识别用户的输入，其中用户需求内容格式是：
            [
              { "name": "<字段名称 1>", "desc": "<字段要求描述 1>", children: [{ "name": "<子字段名称 1>", "desc": "<子字段要求描述 1>" }] },
              { "name": "<字段名称 2>", "desc": "<字段要求描述 2>" }
            ]
            4. 从解析出的信息里，筛选出与之相关的信息。
            
            ### 技能 2: 整合形成文档
            1. 将提取出的相关内容进行系统整理、归纳，以清晰、有条理的方式整合到一起，形成完整的文档。
            2. 全面、系统且有条理地梳理出所有需上交的材料信息，以清晰、准确的方式严格按照如下特定格式列举：
            {
              "data": {
                "<字段名称 1>": "<内容 1>",
                "<字段名称 2>": "<内容 2>",
                "<字段名称 3>": [{ "<子字段名称 1>": "<子内容 1>" }, { "<子字段名称 2>": "<子内容 2>" }]
              },
              "attachment": [
                { "id": "<文件id 1>", "name": "001、<新的文件名称 1>" },
                { "id": "<文件id 2>", "name": "002、<新的文件名称 2>" }
              ],
              "year": "<资料所属年份>",
              "category": "<资料所属类别>"
            }
            3. 字段名称是根据用户输入的字段名称信息信息提取的，然后按照字段要求进行提取内容
            4. 如果用户提供的需要的附件的描述，需要严格根据用户的描述将附件信息提取到attachment处，如果没有提供，则不需要该内容
            5. 资料所属年份需要从用户提供的材料中提取出年份信息相关的年份，其中最准确的一个年份信息作为最终的年份信息
            6. 资料所属类别需要从用户提供的材料中提取出类别信息相关的内容，其中最准确的一个类别信息作为最终的类别信息
            7. 如果不符合要求不要生成对应的内容，返回空数组。
            
            ## 限制:
            - 只专注于提取和整合与目标材料相关的内容，拒绝处理无关信息。
            - attachment如果需要的话，严格筛选出符合要求的信息，尤其是年份信息相关的处理
            - 需正确解析和处理符合要求的代码输入，对于无法解析的输入应提示用户重新提供合适的代码内容。
            """;

    @Resource
    private TaskService taskService;
    @Resource
    private TaskDetailItemService taskDetailItemService;
    @Resource
    private TaskFileCommitService taskFileCommitService;
    @Resource
    private TaskResultGenerateService taskResultGenerateService;
    @Resource
    private ResourceService resourceService;
    @Resource
    private TemplateDetailService templateDetailService;
    @Resource
    private TemplateDetailAttachmentService templateDetailAttachmentService;
    @Resource
    private TemplateDetailAttachmentFieldService templateDetailAttachmentFieldService;

    @Resource
    private VolcengineChatUtil volcengineChatUtil;
    @Resource
    private TaskSseEmitterUtil taskSseEmitterUtil;

    /**
     * 单条信息的处理
     *
     * @return 是否需要继续执行
     */
    @Override
    protected boolean invoke() {
        // 获取第一条未处理的数据
        var item = taskDetailItemService.getFirstNotHandleItem();
        if (item == null) {
            return false;
        }
        generate(item);
        return true;
    }

    /**
     * 根据项目id生成对应的内容
     *
     * @param itemId 项目id
     */
    private void generate(Long itemId) {
        // 查询这个项目的信息
        var item = taskDetailItemService.getPoById(itemId);
        generate(item);
    }

    /**
     * 根据项目id生成对应的内容
     *
     * @param item 详情项
     */
    private void generate(TaskDetailItem item) {
        // 需要修改状态
        taskDetailItemService.updateStatusByItemId(item.getId(), TaskDetailItem.GenerateStatus.GENERATING);
        taskSseEmitterUtil.sendGenerateNotice(item.getFkTaskId(), item.getFkDetailId(), item.getId(), TaskDetailItem.GenerateStatus.GENERATING);
        try {
            // 查询这个任务下的所有提交文件信息（仅用到的那些文件）
            var structureList = taskFileCommitService.listAvailableStructureByTaskId(item.getFkTaskId(), item.getFkDetailId(), item.getId());
            var tupleList = switch (item.getType()) {
                case ConstantCommon.Type.CREATE_BY_CUSTOM_FILE -> createByCustomFile(item, structureList);
                case ConstantCommon.Type.CREATE_BY_TEMPLATE ->
                        createByTemplateKey(item, structureList, item.getFkSourceId());
                default -> throw new BusinessException("不支持的生成方式");
            };
            var generateList = tupleList.stream().map(Tuple2::value1).toList();
            var generateVoList = tupleList.stream().map(Tuple2::value2).toList();
            // 批量通知
            taskResultGenerateService.batchInsert(generateList);
            taskDetailItemService.updateStatusByItemId(item.getId(), TaskDetailItem.GenerateStatus.NORMAL);
            taskSseEmitterUtil.sendGenerateNotice(item.getFkTaskId(), item.getFkDetailId(), item.getId(), TaskDetailItem.GenerateStatus.NORMAL, generateVoList);
        } catch (Exception e) {
            taskDetailItemService.updateStatusByItemId(item.getId(), TaskDetailItem.GenerateStatus.FAILED);
            taskSseEmitterUtil.sendGenerateNotice(item.getFkTaskId(), item.getFkDetailId(), item.getId(), TaskDetailItem.GenerateStatus.FAILED);
        }
    }

    /**
     * 根据自定义文件创建
     *
     * @param item          详情项
     * @param structureList 结构化的数据
     * @return 生成的结果
     */
    private List<Tuple2<TaskResultGenerate, TaskResultGenerateVo>> createByCustomFile(TaskDetailItem item, List<TaskFileCommit.Structure> structureList) {
        return createByCustomFile(item, structureList, null);
    }

    /**
     * 根据自定义文件创建
     *
     * @param item           详情项
     * @param structureList  结构化的数据
     * @param generatePrompt 额外的系统提示词
     * @return 生成的结果
     */
    private List<Tuple2<TaskResultGenerate, TaskResultGenerateVo>> createByCustomFile(
            TaskDetailItem item,
            List<TaskFileCommit.Structure> structureList,
            String generatePrompt
    ) {
        // 全部交由大模型处理
        var result = volcengineChatUtil.invoke(
                SYSTEM_PROMPT,
                String.format("我想要生成的文件名称是：%s，具体的要求内容：%s", item.getTitle(), item.getDescription()),
                JSON.toJSONString(structureList),
                StringUtils.isBlank(generatePrompt) ? "" : generatePrompt,
                "我希望可以生成1份或者多份符合要求的文档信息"
        );
        // 转成结构化的数据
        var array = JSON.parseArray(result);
        var resultList = new ArrayList<Tuple2<TaskResultGenerate, TaskResultGenerateVo>>();
        for (var i = 0; i < array.size(); i++) {
            var r = array.getJSONObject(i);
            var fileName = r.getString("title");
            var description = r.getString("description");
            // 获取文本内容
            var content = r.getString("content");
            var file = FileUtil.write(fileName, ".md", content);
            var tuple = createResultGenerate(item, fileName + ".md", description, file);
            resultList.add(tuple);
        }
        return resultList;
    }

    /**
     * 根据模板key创建
     *
     * @param item             详情项
     * @param structureList    结构化的数据
     * @param templateDetailId 模板详情id
     * @return 生成的结果
     */
    private List<Tuple2<TaskResultGenerate, TaskResultGenerateVo>> createByTemplateKey(
            TaskDetailItem item,
            List<TaskFileCommit.Structure> structureList,
            Long templateDetailId
    ) {
        try {
            // 根据模板详情查询信息
            var templateDetail = templateDetailService.getPoById(templateDetailId);
            return switch (templateDetail.getGenerateType()) {
                // 不生成
                case TemplateDetail.GenerateType.NOT_GENERATE -> List.of();
                // 走自定义生成
                case TemplateDetail.GenerateType.CUSTOM_GENERATE ->
                        createByCustomFile(item, structureList, templateDetail.getGeneratePrompt());
                // 走附件生成
                case TemplateDetail.GenerateType.ATTACHMENT_GENERATE -> {
                    // 查询任务信息
                    var task = taskService.getPoById(item.getFkTaskId());
                    yield generateForAttachmentGenerate(task, item, structureList, templateDetailId);
                }
                // 提取原始材料
                case TemplateDetail.GenerateType.EXTRACT_MATERIAL ->
                        generateForExtractMaterial(item, structureList, templateDetailId);
                default -> throw new BusinessException("不支持的生成方式");
            };
        } catch (Exception e) {
            throw new BusinessException("生成失败：" + e.getMessage());
        }
    }

    /**
     * 根据附件生成信息
     *
     * @param task             任务信息
     * @param item             任务详情信息
     * @param structureList    结构化的数据
     * @param templateDetailId 模板详情id
     * @return 生成的结果
     * @throws Exception 异常信息
     */
    private List<Tuple2<TaskResultGenerate, TaskResultGenerateVo>> generateForAttachmentGenerate(
            Task task,
            TaskDetailItem item,
            List<TaskFileCommit.Structure> structureList,
            Long templateDetailId
    ) throws Exception {
        var structureContent = JSON.toJSONString(structureList);
        // 最终生成的信息
        var resultList = new ArrayList<Tuple2<TaskResultGenerate, TaskResultGenerateVo>>();
        // 查询所有的附件信息，附件是循环生成对应的文件的
        var attachmentList = templateDetailAttachmentService.listByTemplateDetailId(templateDetailId);
        for (var attachment : attachmentList) {
            // 获取字段列表
            var fieldList = templateDetailAttachmentFieldService.listByAttachmentId(attachment.getId());
            var fieldTreeList = fieldList.stream().map(TreeNode::new).toList();
            fieldTreeList = TreeNode.build(fieldTreeList, TemplateDetailAttachmentField::getId, TemplateDetailAttachmentField::getFkParentId);
            // 将字段转成对应的数据信息
            var fieldStructureList = fieldTreeList.stream().map(this::convertFieldStructure).toList();
            var userPromptList = new ArrayList<String>();
            if (StringUtils.isNotBlank(task.getPrompt())) {
                userPromptList.add("这是我的前置提示词信息：" + task.getPrompt());
            }
            if (StringUtils.isNotBlank(task.getRealmName())) {
                userPromptList.add("这个我公司的领域信息：" + task.getRealmName());
            }
            userPromptList.add("我想要生成的文件名称是：" + attachment.getAttachmentName());
            userPromptList.add("材料数据是：" + structureContent);
            userPromptList.add("需要的字段数据是：" + JSON.toJSONString(fieldStructureList));
            // 如果有附件提示语，需要添加附件提示语
            userPromptList.add(StringUtils.isBlank(attachment.getAttachmentPrompt())
                    ? "不需要额外的附件内容信息"
                    : ("我需要的额外附件内容信息是：" + attachment.getAttachmentPrompt())
            );
            userPromptList.add("现在的时间是" + LocalDateTime.now() + "，帮我根据上面提供的材料提取出需要的内容");
            // 全部交由大模型处理
            var result = volcengineChatUtil.invoke(TEMPLATE_SYSTEM_PROMPT, userPromptList);
            var responseMap = JSON.parseObject(result);
            var resultMap = responseMap.getJSONObject("data");
            resolveResultMap(fieldList, resultMap);
            // 获取待下载的文件后缀
            var url = attachment.getAttachmentPath();
            var fileExtension = url.substring(url.lastIndexOf(".")).toLowerCase();
            var sourceFile = File.createTempFile(System.currentTimeMillis() + "", fileExtension);
            HttpUtil.downloadFile(url, sourceFile);
            // 判断文件后缀
            if (fileExtension.endsWith("doc") || fileExtension.endsWith("docx")) {
                // 绑定word渲染的插件
                var builder = bindPolicies(fieldList);
                // 生成文件
                var targetFile = File.createTempFile("template-", fileExtension);
                var template = XWPFTemplate.compile(sourceFile, builder.build()).render(resultMap);
                template.writeAndClose(new FileOutputStream(targetFile));
                // 生成结果
                var tuple = createResultGenerate(item, attachment.getAttachmentName() + fileExtension, "", targetFile);
                resultList.add(tuple);
            }
            if (fileExtension.endsWith("xls") || fileExtension.endsWith("xlsx")) {
                // 定义列表区域
                var regions = fieldList.stream()
                        .filter(field -> field.getType() == TemplateDetailAttachmentField.Type.TABLE_ROW)
                        .map(field -> new ExcelListRegion(field.getName(), String.format("${%s_START}", field.getName()), String.format("${%s_END}", field.getName())))
                        .toList();
                // 查询出所有的列表值
                var listValuesMap = new HashMap<String, List<JSONObject>>();
                fieldList.stream()
                        .filter(field -> field.getType() == TemplateDetailAttachmentField.Type.TABLE_ROW)
                        .forEach(field -> {
                            var list = resultMap.getJSONArray(field.getName());
                            listValuesMap.put(field.getName(), list.stream().map(JSONObject.class::cast).toList());
                        });
                var targetFile = ExcelTemplateUtil.fill(sourceFile, resultMap, regions, listValuesMap);
                // 生成结果
                var tuple = createResultGenerate(item, attachment.getAttachmentName() + fileExtension, "", targetFile);
                resultList.add(tuple);
            }
            // 其他附件
            resultList.addAll(resolveAttachment(responseMap, item));
        }
        return resultList;
    }

    /**
     * 提取原始材料信息
     *
     * @param item             任务详情信息
     * @param structureList    结构化的数据
     * @param templateDetailId 模板详情id
     * @return 生成的结果
     * @throws Exception 异常信息
     */
    private List<Tuple2<TaskResultGenerate, TaskResultGenerateVo>> generateForExtractMaterial(
            TaskDetailItem item,
            List<TaskFileCommit.Structure> structureList,
            Long templateDetailId
    ) throws Exception {
        var templateDetail = templateDetailService.getPoById(templateDetailId);
        var structureContent = JSON.toJSONString(structureList);
        var userPromptList = new ArrayList<String>();
        userPromptList.add("材料数据是：" + structureContent);
        userPromptList.add("我需要的额外附件内容信息是：" + templateDetail.getGeneratePrompt());
        userPromptList.add("现在的时间是" + LocalDateTime.now() + "，帮我根据上面提供的材料提取出需要的内容");
        // 全部交由大模型处理
        var result = volcengineChatUtil.invoke(TEMPLATE_SYSTEM_PROMPT, userPromptList);
        // 其他附件
        return resolveAttachment(JSON.parseObject(result), item);
    }

    /**
     * 提取附件信息
     *
     * @param responseMap 解析数据
     * @param item        任务详情信息
     * @return 生成的结果
     * @throws Exception 异常信息
     */
    private List<Tuple2<TaskResultGenerate, TaskResultGenerateVo>> resolveAttachment(JSONObject responseMap, TaskDetailItem item) throws Exception {
        // 最终生成的信息
        var resultList = new ArrayList<Tuple2<TaskResultGenerate, TaskResultGenerateVo>>();
        if (responseMap.containsKey("attachment")) {
            // 解析附件
            var attachmentArray = responseMap.getJSONArray("attachment");
            for (int i = 0; i < attachmentArray.size(); i++) {
                var attachmentItem = attachmentArray.getJSONObject(i);
                // 查询杜莹的值
                var id = attachmentItem.getLong("id");
                // 去查询对应的文件信息
                var commit = taskFileCommitService.getPoById(id, false);
                if (commit != null) {
                    var tempUrl = commit.getFilePath();
                    var tempFileExtension = tempUrl.substring(tempUrl.lastIndexOf(".")).toLowerCase();
                    var attachmentFile = File.createTempFile("attachment-" + System.currentTimeMillis(), tempFileExtension);
                    HttpUtil.downloadFile(commit.getFilePath(), attachmentFile);
                    var attachmentTuple = createResultGenerate(item, attachmentItem.getString("name") + tempFileExtension, "", attachmentFile);
                    resultList.add(attachmentTuple);
                }
            }
        }
        return resultList;
    }

    /**
     * 渲染绑定插件
     *
     * @param fieldList 字段列表
     */
    private ConfigureBuilder bindPolicies(List<TemplateDetailAttachmentField> fieldList) {
        return bindPolicies(Configure.builder(), fieldList);
    }

    /**
     * 渲染绑定插件
     *
     * @param builder   配置构建器
     * @param fieldList 字段列表
     */
    private ConfigureBuilder bindPolicies(ConfigureBuilder builder, List<TemplateDetailAttachmentField> fieldList) {
        // 绑定表格行插件
        var loopRowTableRenderPolicy = new LoopRowTableRenderPolicy();
        fieldList.stream()
                .filter(i -> i.getType() == TemplateDetailAttachmentField.Type.TABLE_ROW)
                .map(TemplateDetailAttachmentField::getName)
                .forEach(name -> builder.bind(name, loopRowTableRenderPolicy));
        // 绑定表格列插件
        var loopColumnTableRenderPolicy = new LoopColumnTableRenderPolicy();
        fieldList.stream()
                .filter(i -> i.getType() == TemplateDetailAttachmentField.Type.TABLE_COLUMN)
                .map(TemplateDetailAttachmentField::getName)
                .forEach(name -> builder.bind(name, loopColumnTableRenderPolicy));
        return builder;
    }

    /**
     * 创建生成结果
     *
     * @param item        详情项
     * @param fileName    文件名称
     * @param description 描述
     * @param file        生成的文件
     * @return 生成结果
     */
    private Tuple2<TaskResultGenerate, TaskResultGenerateVo> createResultGenerate(
            TaskDetailItem item,
            String fileName,
            String description,
            File file
    ) {
        var po = new TaskResultGenerate();
        po.setFkTaskId(item.getFkTaskId());
        po.setFkDetailId(item.getFkDetailId());
        po.setFkItemId(item.getId());
        po.setFileName(fileName);
        po.setDescription(description);
        // 将文件上传
        var fileRecord = resourceService.upload(file);
        po.setFileName(po.getFileName());
        po.setFkFileId(fileRecord.getId());
        po.setFilePath(fileRecord.getPosition() + fileRecord.getPath());
        po.setGmtCreate(LocalDateTime.now());
        var vo = new TaskResultGenerateVo(po);
        vo.setFileRecord(fileRecord);
        return Tuple.of(po, vo);
    }

    private void resolveResultMap(List<TemplateDetailAttachmentField> fieldList, JSONObject resultMap) {
        // 获取所有的图片字段列表
        var imageFieldList = fieldList.stream().filter(i -> i.getType() == TemplateDetailAttachmentField.Type.IMAGE).toList();
        if (imageFieldList.isEmpty()) {
            return;
        }
        var imageFieldNameList = imageFieldList.stream().map(TemplateDetailAttachmentField::getName).collect(Collectors.toSet());
        // 遍历所有的resultMap
        resolveImageResultMap(resultMap, imageFieldNameList);
    }

    /**
     * 解析图片属性
     *
     * @param resultMap 结果map
     * @param nameList  图片字段名称列表
     */
    private void resolveImageResultMap(JSONObject resultMap, Set<String> nameList) {
        for (var name : nameList) {
            if (resultMap.containsKey(name)) {
                resultMap.put(name, Pictures.ofUrl(resultMap.getString(name)));
            }
        }
        // 获取值是List的字段
        var listItemName = resultMap.entrySet().stream().filter(item -> item.getValue() instanceof List<?>).map(Map.Entry::getKey).toList();
        listItemName.forEach(name -> {
            var array = resultMap.getJSONArray(name);
            for (int i = 0; i < array.size(); i++) {
                var item = array.getJSONObject(i);
                resolveImageResultMap(item, nameList);
            }
        });
    }

    /**
     * 将字段数据转为结构数据
     *
     * @param node 节点
     * @return 结构数据
     */
    private JSONObject convertFieldStructure(TreeNode<TemplateDetailAttachmentField> node) {
        // 获取原对象
        var field = node.getItem();
        // 创建返回对象
        var object = new JSONObject();
        object.put("name", field.getName());
        if (node.getChildren() != null && !node.getChildren().isEmpty()) {
            // 有子节点，需要先处理子节点的信息
            var children = node.getChildren().stream().map(this::convertFieldStructure).toList();
            object.put("children", children);
        }
        var description = field.getDescription();
        if (StringUtils.isNotBlank(field.getDefaultValue())) {
            description += "，默认值" + field.getDefaultValue();
        }
        description += "，" + TemplateDetailAttachmentField.FIELD_TYPE_MAP.getOrDefault(field.getType(), "文本类型");
        // 如果是图片类型的默认是一个图片地址
        if (field.getType() == TemplateDetailAttachmentField.Type.IMAGE) {
            description += "，这是一个图片类型的字段，所以我需要的是一个url链接地址";
        }
        object.put("desc", description);
        return object;
    }

}
